/**
 * @copyright iKnight Studio
 * @file com.iknight.mgr.controller
 * @project mgr-web
 */
package com.iknight.mgr.controller;

import com.iknight.mgr.api.PubCodeService;
import com.iknight.mgr.api.RoleService;
import com.iknight.mgr.api.UserService;
import com.iknight.mgr.core.common.HttpCode;
import com.iknight.mgr.core.common.HttpCodeEnum;
import com.iknight.mgr.core.constant.IkgConstantCode;
import com.iknight.mgr.core.constant.IkgToken;
import com.iknight.mgr.core.shiro.MgrToken;
import com.iknight.mgr.core.tree.MenuTreeNode;
import com.iknight.mgr.core.tree.TreeUtils;
import com.iknight.mgr.core.utils.IkgStringUtils;
import com.iknight.mgr.core.utils.IkgWebUtils;
import com.iknight.mgr.model.RoleModel;
import com.iknight.mgr.model.UserModel;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.Cache;
import org.springframework.cache.ehcache.EhCacheCacheManager;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.*;

/**
 * @author JeryZym
 * @format /rest/*
 */
@RestController
@RequestMapping("/rest")
@Api(protocols = "http", value = "通用控制器", consumes = "基础用户")
public class CommonController {
    private Logger logger = LogManager.getLogger(CommonController.class);

    @Autowired
    private UserService<UserModel, String> userService;
    @Autowired
    private RoleService<RoleModel, String> roleService;
    @Autowired
    private PubCodeService pubCodeService;

    @Autowired
    private EhCacheCacheManager cacheManager;

    /**
     * 前后端分离模式 true 分离 false 混合
     */
    @Value("${seprateMode}")
    private boolean seprateMode;
    @Value("${email_user}")
    private String emailUser;
    @Value("${email_pwd}")
    private String emailPwd;

    /**
     * method-list login/logout/loadMenu
     */
    @PostMapping("/login")
    @ApiOperation(httpMethod = "post", value = "login", nickname = "登录", notes = "登录方法，实现用户信息基本验证")
    public Object login(@RequestBody Map<String, Object> params, HttpServletRequest request,
                        HttpServletResponse response) {

        JSONObject result = new JSONObject();
        result.put("seprateMode", seprateMode);

        if (params == null) {
            result.put("code", HttpCode.HTTP_PARAM_NULL);
            return IkgWebUtils.postIkgResponse(false, "传入参数为空", result);
        }


        String username = IkgStringUtils.ObjectToString(params.get("user_name"));
        if (StringUtils.isEmpty(username)) {
            result.put("code", HttpCodeEnum.HTTP_USER_NULL);
            return IkgWebUtils.postIkgResponse(false, "用户名为空", result);
        }

        String password = IkgStringUtils.ObjectToString(params.get("user_pwd"));
        if (StringUtils.isEmpty(password)) {
            result.put("code", HttpCodeEnum.HTTP_PWD_NULL);
            return IkgWebUtils.postIkgResponse(false, "密码为空", result);
        }

        UserModel user = userService.getUserByUsername(username);
        String encrypt = IkgStringUtils.md5Pwd(password, user.getUser_salt());
        if (StringUtils.equals(encrypt, user.getUser_pwd())) {
            IkgToken token = new IkgToken();
            String id = UUID.randomUUID().toString();
            token.setTokenId(id);
            token.setUsername(user.getUser_id());
            token.setLoginDate(Calendar.getInstance().getTime());
            Map map = new HashMap();
            map.put("name", user.getUser_name());
            token.setInfo(map);
            Cache cache = cacheManager.getCache("userSession");
            cache.put(id, token);

            result.put("code", HttpCodeEnum.HTTP_USER_LOGIN_SUC);
            result.put("tokenId", id);

            return IkgWebUtils.postIkgResponse(true, "登录成功!", result);
        } else {
            result.put("code", HttpCodeEnum.HTTP_USER_PWD_UNMATCH);
            return IkgWebUtils.postIkgResponse(false, "密码不一致", result);
        }
    }

    @PostMapping("/shiroLogin")
    @ApiOperation(httpMethod = "post", value = "shiroLogin", nickname = "shiro登录模式")
    public Object shiroLogin(@RequestBody Map<String, Object> params, HttpServletRequest request,
                             HttpServletResponse response) {
        JSONObject result = new JSONObject();
        result.put("seprateMode", seprateMode);

        if (params == null) {
            result.put("code", HttpCodeEnum.HTTP_PARAM_NULL);
            return IkgWebUtils.postIkgResponse(false, "传入参数为空!", result);
        }

        String username = IkgStringUtils.ObjectToString(params.get("user_name"));
        if (StringUtils.isEmpty(username)) {
            result.put("code", HttpCodeEnum.HTTP_USER_NULL);
            return IkgWebUtils.postIkgResponse(false, "用户名为空!", result);
        }

        String password = IkgStringUtils.ObjectToString(params.get("user_pwd"));
        if (StringUtils.isEmpty(password)) {
            result.put("code", HttpCodeEnum.HTTP_PWD_NULL);
            return IkgWebUtils.postIkgResponse(false, "密码为空!", result);
        }

        Subject currentUser = SecurityUtils.getSubject();
        if (currentUser.isAuthenticated()) {
            String user = String.valueOf(currentUser.getPrincipal());
            Object def_uri = roleService.getRoleDefinedURIByUsername(user);
            String def_uri_str = def_uri == null ? "" : String.valueOf(def_uri);

            result.put("code", HttpCodeEnum.HTTP_USER_ONLINE);
            if (!seprateMode) {
                result.put("redirectUri", request.getContextPath() + def_uri_str);
            }
            return IkgWebUtils.postIkgResponse(true, "用户已登录!", result);
        }

        UserModel user = userService.getUserByUsername(username);
        if (null == user) {
            result.put("code", HttpCodeEnum.HTTP_USER_NO_EXISTS);
            return IkgWebUtils.postIkgResponse(false, "用户不存在!", result);
        }
        String encrypt = IkgStringUtils.md5Pwd(password, user.getUser_salt());

        if (!StringUtils.equals(encrypt, user.getUser_pwd())) {
            result.put("code", HttpCodeEnum.HTTP_USER_PWD_ERROR);
            return IkgWebUtils.postIkgResponse(false, "密码错误,请重试!", result);
        }

        String host = request.getRemoteHost();
        MgrToken token = new MgrToken(username, password, host, user.getUser_id(), user.getUser_pwd(),
                user.getUser_salt());
        try {
            currentUser.login(token);
            token.setRememberMe(true);

            Object def_uri = roleService.getRoleDefinedURIByUsername(user.getUser_name());
            String def_uri_str = def_uri == null ? "/default.cmd" : String.valueOf(def_uri);

            IkgToken ikgToken = new IkgToken();
            String id = UUID.randomUUID().toString();
            ikgToken.setTokenId(id);
            ikgToken.setUserId(user.getUser_id());
            ikgToken.setLoginDate(Calendar.getInstance().getTime());
            Map map = new HashMap();
            map.put("name", user.getUser_name());
            ikgToken.setInfo(map);

            Cache cache = cacheManager.getCache("shiroUserSession");
            cache.put(id, token);

            result.put("code", HttpCodeEnum.HTTP_USER_LOGIN_SUC);
            result.put("tokenId", id);

            if (!seprateMode) {
                result.put("redirectUri", request.getContextPath() + def_uri_str);
            }
            return IkgWebUtils.postIkgResponse(true, "登录成功!", result);
        } catch (Exception e) {
            logger.debug(e.getMessage());
            result.put("code", HttpCodeEnum.HTTP_USER_LOGIN_EXCEPTION);
            return IkgWebUtils.postIkgResponse(false, e.getMessage(), result);
        }
    }

    @PostMapping("/logout")
    public Object logout(HttpServletRequest request, HttpServletResponse response) {
        HttpSession session = request.getSession();
        session.invalidate();
        JSONObject result = new JSONObject();
        result.put("code", HttpCodeEnum.HTTP_USER_LOGOUT_SUC);
        return IkgWebUtils.postIkgResponse(true, "登出成功!", result);
    }

    @PostMapping("/shiroLogout")
    @ApiOperation(httpMethod = "post", value = "logout", nickname = "登出方法")
    public Object shiroLogout(HttpServletRequest request, HttpServletResponse response) {
        JSONObject result = new JSONObject();
        result.put("seprateMode", seprateMode);

        Subject currentUser = SecurityUtils.getSubject();
        if (currentUser == null) {
            result.put("code", IkgConstantCode.SESSIONEXPIRED);
            return IkgWebUtils.postIkgResponse(true, "缓存已失效!", result);
        }
        currentUser.logout();

        result.put("code", HttpCodeEnum.HTTP_USER_LOGOUT_SUC);

        if (!seprateMode) {
            result.put("redirectUri", request.getContextPath() + "/login.cmd");
        }
        return IkgWebUtils.postIkgResponse(true, "登出成功!", result);
    }

    @SuppressWarnings({"rawtypes"})
    @PostMapping("/loadMenu")
    @RequiresPermissions("ikg.sys.loadMenu")
    public Object loadMenu(HttpServletRequest request, HttpServletResponse response) {

        JSONObject result = new JSONObject();
        result.put("seprateMode", seprateMode);

        Subject currentUser = SecurityUtils.getSubject();

        if (currentUser == null || currentUser.getPrincipals() == null || currentUser.getPrincipal() == null) {
            try {
                org.apache.shiro.web.util.WebUtils.issueRedirect(request, response, "");
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            result.put("code", HttpCodeEnum.HTTP_USER_SESSION_EXPIRED);
            return IkgWebUtils.postIkgResponse(false, "未检测到用户登录信息,请重新登录!", result);
        }
        String username = String.valueOf(currentUser.getPrincipal());
        List<Map> authMenus = roleService.getMenusByUsername(username);
        if (authMenus == null) {
            return null;
        }
        List<MenuTreeNode> nodes = new ArrayList<MenuTreeNode>();
        for (Map map : authMenus) {
            MenuTreeNode node = new MenuTreeNode();
            node.setId(IkgStringUtils.ObjectToString(map.get("menu_id")));
            node.setPid(IkgStringUtils.ObjectToString(map.get("p_menu_id")));
            node.setText(IkgStringUtils.ObjectToString(map.get("menu_name")));
            node.setIcon(IkgStringUtils.ObjectToString(map.get("icon_cls")));
            node.setUrl(IkgStringUtils.ObjectToString(map.get("menu_uri")));
            node.setTemplate_uri(IkgStringUtils.ObjectToString(map.get("template_uri")));
            node.setScript_uri(IkgStringUtils.ObjectToString(map.get("script_uri")));
            nodes.add(node);
        }
        List<MenuTreeNode> menuTree = TreeUtils.getRootNode(nodes);
        return JSONArray.fromObject(menuTree);
    }

    @PostMapping("/regist")
    public Object registerUser(@RequestBody Map<String, Object> params, HttpServletRequest request,
                               HttpServletResponse response) {
        return null;
    }

    @PostMapping("/uuid")
    public String getUUID(HttpServletRequest request, HttpServletResponse response) {
        System.out.println("generate UUID ing");
        return UUID.randomUUID().toString();
    }

    @PostMapping("/unauthorized")
    public Object unauthorized(HttpServletRequest request, HttpServletResponse response) {
        JSONObject result = new JSONObject();
        result.put("seprateMode", seprateMode);
        result.put("code", IkgConstantCode.UNAUTHORIZE);
        result.put("redirectUri", request.getContextPath() + "/unauthorized.cmd");

        return IkgWebUtils.postIkgResponse(false, "资源未授权", result);
    }

    /**
     * @param request
     * @param response
     * @return
     */
    @PostMapping("/relogin")
    public Object redirectLogin(HttpServletRequest request, HttpServletResponse response) {
        logger.debug("如果一次登录解决不了问题，那就找管理员吧");
        JSONObject result = new JSONObject();
        result.put("seprateMode", seprateMode);
        result.put("code", IkgConstantCode.RELOGIN);

        if (!seprateMode) {
            result.put("redirectUri", request.getContextPath() + "/login.cmd");
        }
        return IkgWebUtils.postIkgResponse(false, "跳转至登录页", result);
    }

    @PostMapping("/getCurrentUserInfo")
    public Object getCurrentUserInfo(HttpServletRequest request, HttpServletResponse response) {
        String username = IkgWebUtils.getCurrentUser();
        if (IkgStringUtils.isNull(username)) {
            return null;
        }
        return JSONObject.fromObject(userService.getUserByUsername(username));
    }

    @PostMapping("/sendMailValidate")
    public Object sendMailValidate(@RequestBody Map<String, Object> params, HttpServletRequest request,
                                   HttpServletResponse response) {

        String targetMail = params.get("registerUser").toString();
        Properties props = new Properties();
        Session session = Session.getDefaultInstance(props);
        MimeMessage message = new MimeMessage(session);
        try {
            message.setFrom(new InternetAddress(this.emailUser, "UTF-8"));
            message.setRecipient(MimeMessage.RecipientType.TO, new InternetAddress(targetMail, "UTF-8"));
            message.setSubject("燕子坞用户注册验证", "UTF-8");
            message.setContent("注册验证码", "text/html;charset=UTF-8");
            message.setSentDate(new Date());
            message.saveChanges();
            Transport transport = session.getTransport();
            transport.connect(this.emailUser, this.emailPwd);
            transport.sendMessage(message, message.getAllRecipients());
            transport.close();
        } catch (UnsupportedEncodingException | MessagingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }

    @PostMapping("/getPubCodeById")
    public Object getPubCodeByPid(@RequestBody Map<String, Object> params, HttpServletRequest request, HttpServletResponse response) {
        String parantId = IkgStringUtils.ObjectToString(params.get("pid"));
        List<Map> result = pubCodeService.getPubCodeByPId(parantId);
        return IkgWebUtils.postIkgResponse(true, "查询成功!", result);
    }

    @PostMapping("/sessionExpired")
    public Object sessionExpired(HttpServletRequest request, HttpServletResponse response) {
        JSONObject result = new JSONObject();
        result.put("seprateMode", seprateMode);
        result.put("code", IkgConstantCode.RELOGIN);
        logger.debug("会话超时，请重新登录!");
        if (!seprateMode) {
            result.put("redirectUri", request.getContextPath() + "/login.cmd");
        }
        return IkgWebUtils.postIkgResponse(false, "会话超时，请重新登录", result);
    }
}
